home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / prog / xlisp21.zip / QA.LSP < prev    next >
Text File  |  1988-02-12  |  39KB  |  1,243 lines

  1. ;========================================================================
  2. ;
  3. ;   qa.lsp - Question answering program using set-of-support
  4. ;            unit-preference resolution principles.
  5. ;
  6. ;   Author: John W. Ward (jwward)
  7. ;   Date:   06-Dec-86
  8. ;
  9. ;       The following program was written for an Artificial Intelligence
  10. ;   class at Kent State University.  The testing sequence used was designed
  11. ;   specifically to fit class requirements.  The program is offered for
  12. ;   inspection and experimentation.  The only claim I make regarding the
  13. ;   program is that I enjoyed working on it and learned something from it.
  14. ;
  15. ;       Some of the algorithms and examples follow our textbook: Artificial
  16. ;   Intelligence, by Elaine Rich (McGraw-Hill, 1983).
  17. ;
  18. ;-------------------------------------------------------------------------
  19. ;
  20. ;       Known limitations: The program degrades quickly when there is
  21. ;   a relatively high branching factor (i.e. many possible paths).  When
  22. ;   the pairs variable gets too big, something nasty usually happens.  On
  23. ;   my machine the something nasty is a warm restart.
  24. ;
  25. ;       The program was written in XLISP 1.7.  Converted to XLISP 2.0
  26. ;   by David Betz.
  27. ;
  28. ;-------------------------------------------------------------------------
  29. ;   QA.LOG provides a transcript of a program session.
  30. ;-------------------------------------------------------------------------
  31. ;
  32. ;   Question-answering is done as follows:
  33. ;   1) The question is negated, then converted to clause form with the
  34. ;      original question tacked on in a $SUCCESS$ "literal".
  35. ;   2) Each clause of the question is paired with all members of base,
  36. ;      producing the original "pairs" list.  Insertion to the list are
  37. ;      according to size of smaller clause * 1000 + size of larger clause.
  38. ;      Each clause is then added to the "base", which thus contains the
  39. ;      set-of-support as well.
  40. ;   3) Until solution is found (and user specifies QUIT) or "pairs" is
  41. ;      exhausted or the number of pairs tested exceeds a set limit (400):
  42. ;      a) Take the next pair of clauses from "pairs".  Try to resolve by
  43. ;         attempting to unify any pair of literals having opposite sign.
  44. ;      b) If the unification is successful, produce the resolution.
  45. ;         If resolution produces a clause already in the base, ignore it.
  46. ;         Otherwise, if the resolution is a success state, display and
  47. ;            ask the user for MORE or QUIT.
  48. ;         Otherwise (new, non-success result), add the result paired with
  49. ;            all current members of the base cum set-of-support to "pairs",
  50. ;            then add the result to the base.
  51. ;
  52. ;   Practically, this thing is slow and perverse.  It's amazing how long
  53. ;   it takes to exhaust the possibilities of an obviously wrong path.
  54. ;
  55. ;   Data structures and variables:
  56. ;       base            - List of hypotheses and set-of-support. The
  57. ;                         set-of-support can be distinguished by a $success$
  58. ;                         clause.  Each clause is actually a list, with the
  59. ;                         clause proceeded by its literal-count.
  60. ;       pairs           - List of clause-pairs to consider for resolution.
  61. ;                         Entries are triples - combined literal-count,
  62. ;                         left-clause and right-clause.  Sorted on ascending
  63. ;                         literal-count, with new entries following old ones
  64. ;                         to provide results analogous to a breadth-first
  65. ;                         search.  (New preceding old ends up close to depth-
  66. ;                         first.)
  67. ;       q-clause        - S-o-s clause currently under consideration (LHS)
  68. ;       b-clause        - Base clause currently under consideration (RHS)
  69. ;       subst-list      - Composition of all substitutions used in
  70. ;                         resolution.  This can be applied to the
  71. ;                         query to produce a solution.  (I hope!)
  72. ;       names           - Names in use in the base including variable names,
  73. ;                         predicates, and Skolem functions.  The type of
  74. ;                         each name will be attached to it.
  75. ;                         (I will convert variables on initial entry into
  76. ;                         the base or query, thus avoiding renaming later.
  77. ;                         I hope!)
  78. ;
  79. ;   Naming:
  80. ;       Constants       - begin with letters A through F or with $.
  81. ;                         (XLISP converts input to upper-case, so I can't
  82. ;                         distinguish that way.)
  83. ;       Variables       - Begin with G through Z.
  84. ;
  85. ;       Associate with every element of a clause is its type - CONSTANT or
  86. ;           VARIABLE.
  87. ;
  88. ;=========================================================================
  89. ;
  90. (alloc 1000)
  91. (expand 20)
  92. ;
  93. ;-------------------------------------------------------------------
  94. ;
  95. ;   qa - main routine
  96. ;
  97. ;   The program is in assert or question mode.  In question mode,
  98. ;       it will attempt to answer the question given by the user.  In
  99. ;       assert mode, it will add to the fact base.
  100. ;
  101. ;   Special commands:
  102. ;       assert    - Change to assert mode
  103. ;       question  - Change to question mode
  104. ;       end       - Start with a new base of information
  105. ;       nil       - End the program
  106. ;
  107. ;-------------------------------------------------------------------
  108. (defun qa ()
  109.     ; First time
  110.     (init-qa)
  111.  
  112.     ; Main loop for each base set
  113.     (do
  114.         ()  ; No initialization
  115.         ((or (null in-line) (equal in-line 'end)))
  116.  
  117.         (setq in-line (get-input mode))
  118.         (cond
  119.             ((null in-line) nil)
  120.             ((equal in-line 'end) (init-qa))
  121.             ((equal in-line 'assert) (setq mode in-line))
  122.             ((equal in-line 'question) (setq mode in-line))
  123.             ((equal in-line 'base)
  124.                 (mapcar `(lambda (a) (print (cadr a))) base)
  125.             )
  126.             ((equal in-line 'proof)
  127.                 (setq show-proof (not show-proof))
  128.                 (cond
  129.                     (show-proof (princ "Resolutions will be shown.\n"))
  130.                     (t (princ "Only answers will be shown.\n"))
  131.                 )
  132.             )
  133.             ((equal in-line 'unify)
  134.                 (setq show-unify (not show-unify))
  135.                 (cond
  136.                     (show-unify (princ "Unifications will be shown.\n"))
  137.                     (t (princ "Unifications will not be shown.\n"))
  138.                 )
  139.             )
  140.             ((equal in-line 'pairs)
  141.                 (setq show-pairs (not show-pairs))
  142.                 (cond
  143.                     (show-pairs (princ "Clause-pairs will be shown.\n"))
  144.                     (t (princ "Clause-pairs will be shown.\n"))
  145.                 )
  146.             )
  147.             ((equal in-line 'help) (give-help))
  148.             ((equal mode 'question) (answer in-line))
  149.             (t (assume in-line))
  150.         )
  151.     )
  152. )
  153. ;
  154. ;-------------------------------------------------------------------
  155. ;
  156. ;   Provide simple help messages
  157. ;
  158. (defun give-help ()
  159.     (princ "\n\n\tQA - Help\n\n")
  160.     (princ "Commands:\n")
  161.     (princ "\tNil to exit, End to restart\n")
  162.     (princ "\tProof, Unify, and Pairs toggle display settings\n")
  163.     (princ "\tAssert      - Shift to assertion mode\n")
  164.     (princ "\tQuestion    - Shift to question mode\n")
  165.     (princ "\tBase        - Display base assumptions\n")
  166.     (princ "\tHelp        - Print this message\n")
  167.     (princ "\nInput form:\n\n")
  168.     (princ "\tConstants begin with letters A-E or $.\n\n")
  169.     (princ "\tEnter assertions or questions in LISP-like form.  You may\n")
  170.     (princ "include the operators AND, OR, NOT, IMPLY, AND EQUIV.  Thus,\n")
  171.     (princ "to indicate that a male parent is a father, type:\n\n")
  172.     (princ "\t(EQUIV (AND ($PARENT X Y) ($MALE X)) ($FATHER X Y))\n\n")
  173.     (princ "The definition of commutative binary operations is:\n\n")
  174.     (princ "\t(IMPLY ($COMMUT K) (EQUIV (K X Y Z) (K Y X Z)))\n")
  175. )
  176. ;-------------------------------------------------------------------
  177. ;
  178. ;   Attempt to answer the question
  179. ;
  180. (defun answer (question)
  181.     (let
  182.         (
  183.             (c-question nil)
  184.         )
  185.         (setq pairs nil)
  186.         (setq
  187.             c-question
  188.             (clause-convert `(or (not ,question) ($success$ ,question)))
  189.         )
  190.         (cond
  191.             ((equal (car c-question) 'and)
  192.                 (setq c-question (mapcar 'set-types c-question))
  193.                 (mapcar 'add-sos (cdr c-question))
  194.             )
  195.             (t
  196.                 (setq c-question (set-types c-question))
  197.                 (add-sos c-question)
  198.             )
  199.         )
  200.         (solve)
  201.         (princ "\n\nDone.\n\n")
  202.         (setq base (remove-success base))
  203.     )
  204. )
  205. ;
  206. ;-------------------------------------------------------------------
  207. ;
  208. ;   Find solution to the question -
  209. ;
  210. ;
  211. ;   pairs = (question X base) from set-up
  212. ;   done <-- nil
  213. ;   While pairs != nil and done == nil {
  214. ;       pair <-- (car pairs); pairs <-- (cdr pairs);
  215. ;       Get q-clause and b-clause from pair
  216. ;           <<< solve-clause-clause >>>
  217. ;           For each q-literal in q-clause {
  218. ;               <<< solve-lit-clause >>>
  219. ;               For each b-literal of opposite sign in b-clause {
  220. ;                   <<< solve-lit-lit >>>
  221. ;                   subs <-- unification of q-literal and b-literal
  222. ;                   If subs != nil {
  223. ;                       Make subs in q-clause and b-clause
  224. ;                       resolution <-- resolve of q-clause and b-clause
  225. ;                       <<< resolved >>>
  226. ;                           Report resolution
  227. ;                           If resolution is a success-state {
  228. ;                               return true if they don't want More
  229. ;                           }
  230. ;                           else {
  231. ;                               add (resolution X base) to pairs
  232. ;                               add resolution to base
  233. ;                               return nil (keep going)
  234. ;                           }
  235. ;                   }
  236. ;               }
  237. ;           }
  238. ;   }
  239. ;
  240. ;
  241. (defun solve ()
  242.     (setq solutions-found nil)
  243.     (setq pairs-count 0)
  244.     (do
  245.         (
  246.             (done nil)
  247.             (pair nil)
  248.         )
  249.         (
  250.             (or done (null pairs) (>= pairs-count max-pairs))
  251.         )
  252.         (setq pair (car pairs))
  253.         (setq pairs (cdr pairs))
  254.  
  255.         (setq q-clause (cadr pair))
  256.         (setq b-clause (caddr pair))
  257.  
  258.         (setq done (solve-clause-clause))
  259.     )
  260. )
  261. ;-------------------------------------------------------------------
  262. ;
  263. ;   Test if result is a success
  264. ;
  265. ;
  266. (defun success-p (clause)
  267.     (cond
  268.         ((atom clause) nil)
  269.         ((equal (car (first-lit clause)) '$success$) t)
  270.         (t nil)
  271.     )
  272. )
  273. ;-------------------------------------------------------------------
  274. ;
  275. ;   Solve given two clauses - pass on with full clauses for later
  276. ;       breakup
  277. ;
  278. ;           <<< solve-clause-clause >>>
  279. ;           Add b-clause to right-used
  280. ;           For each q-literal in q-clause {
  281. ;               <<< solve-lit-clause >>>
  282. ;           }
  283. ;
  284. (defun solve-clause-clause ()
  285.     (cond
  286.         (show-pairs
  287.             (princ "Working on clauses:\n")
  288.             (print q-clause)
  289.             (print b-clause)
  290.             (terpri)
  291.         )
  292.     )
  293.     (setq pairs-count (1+ pairs-count))
  294.     (cond
  295.         ((equal (rem pairs-count 50) 0)
  296.             (princ "Pairs count:\t") (print pairs-count)
  297.             (princ "Base:\t\t")  (print (length base))
  298.             (princ "Pairs:\t\t") (print (length pairs))
  299.             (princ "Size:\t\t")  (print (deep-count pairs))
  300.             (terpri)
  301.             (gc)
  302.             (mem)
  303.             (terpri)
  304.         )
  305.     )
  306.  
  307.     (solve-clause-clause* (remove-success q-clause) (remove-success b-clause))
  308. )
  309. (defun solve-clause-clause* (q-work b-work)
  310.     (let
  311.         (
  312.             (result nil)
  313.         )
  314.         (cond
  315.             ((null b-work) nil)
  316.             ((atom b-work)
  317.                 (princ "Error in solve-clause-clause* - b-work is atom\n")
  318.                 nil
  319.             )
  320.             ((null q-work) nil)
  321.             ((atom q-work)
  322.                 (princ "Error in solve-clause-clause* - q-work is atom\n")
  323.                 nil
  324.             )
  325.             (
  326.                 (setq result (solve-lit-clause (first-lit q-work) b-work))
  327.                 result
  328.             )
  329.             (t (solve-clause-clause* (remove-first-lit q-work) b-work))
  330.         )
  331.     )
  332. )
  333. ;-------------------------------------------------------------------
  334. ;
  335. ;   Solve with a question literal and a base clause
  336. ;
  337. ;               <<< solve-lit-clause >>>
  338. ;               For each b-literal of opposite sign in b-clause {
  339. ;                   <<< solve-lit-lit >>>
  340. ;               }
  341. ;
  342. ;
  343. (defun solve-lit-clause (q-lit b-work)
  344.     (let
  345.         (
  346.             (result nil)
  347.         )
  348.         (cond
  349.             ((null q-lit) nil)
  350.             ((atom q-lit)
  351.                 (princ "Error in solve-lit-clause - q-lit is atom\n")
  352.                 nil
  353.             )
  354.             ((null b-work) nil)
  355.             ((atom b-work)
  356.                 (princ "Error in solve-lit-clause - b-work is atom\n")
  357.                 nil
  358.             )
  359.             ((setq result (solve-lit-lit q-lit (first-lit b-work))) result)
  360.             (t (solve-lit-clause q-lit (remove-first-lit b-work)))
  361.         )
  362.     )
  363. )
  364. ;-------------------------------------------------------------------
  365. ;
  366. ;   Solve with a question literal and a base literal
  367. ;
  368. ;                   <<< solve-lit-lit >>>
  369. ;                   subs <-- unification of q-literal and b-literal
  370. ;                   If subs != nil {
  371. ;                       Make subs in q-clause and b-clause
  372. ;                       resolution <-- resolve of q-clause and b-clause
  373. ;                       If resolution != nil {
  374. ;                           <<< resolved >>>
  375. ;                       }
  376. ;                   }
  377. ;
  378. ;
  379. (defun solve-lit-lit (q-lit b-lit)
  380.     (let
  381.         (
  382.             (subs nil)
  383.             (resolution nil)
  384.             (old-q q-clause)
  385.             (old-b b-clause)
  386.         )
  387.  
  388.         ; Quit without effort if literals are not of opposite sign
  389.         (cond
  390.             ((equal (lit-sign q-lit) (lit-sign b-lit)) nil)
  391.             (t
  392.                 (setq subs (unify q-lit b-lit))
  393.                 (cond
  394.                     (show-unify
  395.                         (princ "Unification of: ") (print q-lit)
  396.                         (princ "           and: ") (print b-lit)
  397.                         (princ "            is: ") (print subs)
  398.                         (terpri)
  399.                     )
  400.                 )
  401.                 (cond
  402.                     ((not (null subs))
  403.                         (setq old-q (make-subs subs q-clause))
  404.                         (setq old-b (make-subs subs b-clause))
  405.                         (setq resolution (resolve old-q old-b))
  406.                         (cond
  407.                             (
  408.                                 (not
  409.                                     (member
  410.                                         (add-count resolution)
  411.                                         base :test #'equal
  412.                                     )
  413.                                 )
  414.                                 (resolved resolution)
  415.                             )
  416.                             (t nil)
  417.                         )
  418.                     )
  419.                     (t nil)
  420.                 )
  421.             )
  422.         )
  423.     )
  424. )
  425. ;-------------------------------------------------------------------
  426. ;
  427. ;   Handle a successful resolution
  428. ;
  429. ;                           Report resolution
  430. ;                           If resolution is a success-state {
  431. ;                               done <-- quit if they don't want More
  432. ;                           }
  433. ;                           else {
  434. ;                               add (resolution X base) to pairs
  435. ;                               add resolution to base
  436. ;                               return nil for resolution
  437. ;                           }
  438. ;
  439. (defun resolved (resolution)
  440.     (cond
  441.         (show-proof
  442.             (terpri)
  443.             (princ "Clause 1   ") (print q-clause)
  444.             (princ "Clause 2   ") (print b-clause)
  445.             (princ "Resolution ") (print resolution)
  446.             (terpri)
  447.         )
  448.     )
  449.     (cond
  450.         ((success-p resolution)
  451.             (cond
  452.                 (
  453.                     (not
  454.                         (member
  455.                             resolution
  456.                             solutions-found :test #'equal
  457.                         )
  458.                     )
  459.                     (setq
  460.                         solutions-found
  461.                         (append solutions-found (list resolution))
  462.                     )
  463.                     (print (first-lit resolution))
  464.                     (terpri)
  465.                     (princ "Enter QUIT to quit, MORE for more solutions --")
  466.                     (equal (read) 'quit)
  467.                 )
  468.                 (t nil)
  469.             )
  470.         )
  471.         (t
  472.             (add-sos resolution)
  473.             nil
  474.         )
  475.     )
  476. )
  477. ;-------------------------------------------------------------------
  478. ;
  479. ;   Determine sign of literal (either NOT or NIL)
  480. ;
  481. ;
  482. (defun lit-sign (lit)
  483.     (cond
  484.         ((atom lit) nil)
  485.         ((equal (car lit) 'not) 'not)
  486.         (t nil)
  487.     )
  488. )
  489. ;-------------------------------------------------------------------
  490. ;
  491. ;   Return the "absolute value" (NOT removed) of lit
  492. ;
  493. ;
  494. (defun lit-abs (lit)
  495.     (cond
  496.         ((null (lit-sign lit)) lit)
  497.         (t (cadr lit))
  498.     )
  499. )
  500. ;-------------------------------------------------------------------
  501. ;
  502. ;   Return the negation of a literal
  503. ;
  504. ;
  505. (defun lit-negative (lit)
  506.     (cond
  507.         ((null (lit-sign lit)) `(not ,lit))
  508.         (t (cadr lit))
  509.     )
  510. )
  511. ;-------------------------------------------------------------------
  512. ;
  513. ;   Unify two literals - (from the book, page 156)
  514. ;
  515. ;
  516. (defun unify (q-lit b-lit)
  517.     (unify* (lit-abs q-lit) (lit-abs b-lit) nil)
  518. )
  519. (defun unify* (q-lit b-lit subs)
  520.     (cond
  521.         ; If either is an atom, they must be equal or
  522.         ;       at least one a variable, else fail
  523.         ((or (atom q-lit) (atom b-lit))
  524.             (cond
  525.                 ((equal q-lit b-lit) (compose subs '(nil nil)))
  526.                 ((variable-p b-lit) (compose subs (ok-sub b-lit q-lit)))
  527.                 ((variable-p q-lit) (compose subs (ok-sub q-lit b-lit)))
  528.                 (t nil)
  529.             )
  530.         )
  531.  
  532.         ; We get here for lists
  533.         ((/= (length q-lit) (length b-lit)) nil)
  534.         (t
  535.             (setq subs (unify* (car q-lit) (car b-lit) subs))
  536.             (cond
  537.                 ((null subs) nil)
  538.                 (t
  539.                     (unify*
  540.                         (make-subs subs (cdr q-lit))
  541.                         (make-subs subs (cdr b-lit))
  542.                         subs
  543.                     )
  544.                 )
  545.             )
  546.         )
  547.     )
  548. )
  549. ;-------------------------------------------------------------------
  550. ;
  551. ;   Return nil if y contains x, else return (x y)
  552. ;
  553. ;
  554. (defun ok-sub (x y)
  555.     (cond
  556.         ((deep-member x y) nil)
  557.         (t `(,x ,y))
  558.     )
  559. )
  560. ;-------------------------------------------------------------------
  561. ;
  562. ;   Compose single substitution y into list x
  563. ;
  564. ;
  565. (defun compose (x y)
  566.     (let
  567.         (
  568.             (result nil)
  569.         )
  570.         (cond
  571.             ((null y) nil)
  572.             ((null x) (list y))
  573.             ((equal x '((nil nil))) (list y))
  574.             (t
  575.                 (setq x (sub-right-side y x))
  576.                 (cond
  577.                     ((assoc (car y) x) x)
  578.                     (t (append x (list y)))
  579.                 )
  580.             )
  581.         )
  582.     )
  583. )
  584. ;-------------------------------------------------------------------
  585. ;
  586. ;   Make all substitutions sub (a b) into substitution list
  587. ;       of the form ((x a)) --> ((x b))
  588. ;
  589. ;
  590. (defun sub-right-side (sub sub-list)
  591.     (mapcar `(lambda (x) (sub-right-side* ',sub x)) sub-list)
  592. )
  593. (defun sub-right-side* (sub sub-entry)
  594.     (cons
  595.         (car sub-entry)
  596.         (make-subs (list sub) (cdr sub-entry))
  597.     )
  598. )
  599. ;-------------------------------------------------------------------
  600. ;
  601. ;   Is x variable?
  602. ;
  603. ;
  604. (defun variable-p (x)
  605.     (cond
  606.         ((null x) nil)
  607.         ((atom x) (equal (get x 'type) 'variable))
  608.         (t nil)
  609.     )
  610. )
  611. ;-------------------------------------------------------------------
  612. ;
  613. ;   Resolve two unified clauses
  614. ;
  615. ;
  616. (defun resolve (clause-1 clause-2)
  617.     (let
  618.         (
  619.             (result nil)
  620.         )
  621.         (setq success-list '(or))
  622.         (setq clause-1 (strip-success clause-1))
  623.         (setq clause-2 (strip-success clause-2))
  624.  
  625.         (setq result (load-lits (lit-factor clause-1) '(or)))
  626.         (setq result (load-lits (lit-factor clause-2) result))
  627.         (setq result (load-lits success-list result))
  628.         result
  629.     )
  630. )
  631. ;-------------------------------------------------------------------
  632. ;
  633. ;   Return clause less all $success$ literals and record $success$
  634. ;       literals in success-list
  635. ;
  636. ;
  637. (defun strip-success (clause)
  638.     (cond
  639.         ((null clause) nil)
  640.         ((atom clause) nil)     ; Should be an error
  641.         ((equal (car clause) '$success$)
  642.             (setq success-list (load-lits clause success-list))
  643.             nil
  644.         )
  645.         ((literal-p clause) clause)
  646.         (t                              ; Begins with OR
  647.             (remove
  648.                 nil
  649.                 (cons (car clause) (mapcar 'strip-success (cdr clause)))
  650.             )
  651.         )
  652.     )
  653. )
  654. ;-------------------------------------------------------------------
  655. ;
  656. ;   Before we turn the clauses loose on each other, factor any
  657. ;   internally repeated literals.  If there are internal opposite
  658. ;   literals, return nil, thus letting the other clauses be unaffected
  659. ;   by the tautology.
  660. ;
  661. ;
  662. (defun lit-factor (clause)
  663.     (lit-factor* clause '(or))
  664. )
  665. (defun lit-factor* (clause new-clause)
  666.     (let
  667.         (
  668.             (first (first-lit clause))
  669.             (rest (remove-first-lit clause))
  670.         )
  671.         (cond
  672.             ((null clause) new-clause)
  673.             ((member first new-clause :test #'equal)
  674.                 (lit-factor* rest new-clause)
  675.             )
  676.             ((member (lit-negative first) new-clause :test #'equal) nil)
  677.             (t (lit-factor* rest (append new-clause (list first))))
  678.         )
  679.     )
  680. )
  681. ;-------------------------------------------------------------------
  682. ;
  683. ;   Add literals to clause -
  684. ;       If literal's negative is in clause, remove from both clauses
  685. ;       If literal is in clause, don't add it.
  686. ;       Otherwise add at end of clause
  687. ;
  688. ;
  689. (defun load-lits (clause new-clause)
  690.     (let
  691.         (
  692.             (first (first-lit clause))
  693.             (rest (remove-first-lit clause))
  694.             (negative nil)
  695.         )
  696.         (setq negative (lit-negative first))
  697.         (cond
  698.             ((null clause) new-clause)
  699.             ((member first new-clause :test #'equal)
  700.                 (load-lits rest new-clause)
  701.             )
  702.             ((member negative new-clause :test #'equal)
  703.                 (load-lits rest (remove negative new-clause :test #'equal))
  704.             )
  705.             (t (load-lits rest (append new-clause (list first))))
  706.         )
  707.     )
  708. )
  709. ;-------------------------------------------------------------------
  710. ;
  711. ;   Make substitutions from substitution list
  712. ;
  713. (defun make-subs (subs clause)
  714.     (let
  715.         (
  716.             (pair nil)
  717.         )
  718.         (cond
  719.             ((null clause) nil)
  720.             ((atom clause)
  721.                 (setq pair (assoc clause subs))
  722.                 (cond
  723.                     ((null pair) clause)
  724.                     (t (cadr pair))
  725.                 )
  726.             )
  727.             (t (mapcar `(lambda (x) (make-subs ',subs x)) clause))
  728.         )
  729.     )
  730. )
  731. ;-------------------------------------------------------------------
  732. ;
  733. ;   Add fact to the base hypotheses
  734. ;
  735. ;   Convert the fact to clause form.
  736. ;   If the result is a conjuction of clauses, set types and add them all;
  737. ;   else set the types and add the single clause.
  738. ;
  739. (defun assume (fact)
  740.     (setq fact (clause-convert fact))
  741.     (cond
  742.         ((equal (car fact) 'and)
  743.             (setq fact (mapcar 'set-types fact))
  744.             (setq base (append base (mapcar 'add-count (cdr fact))))
  745.         )
  746.         (t
  747.             (setq fact (set-types fact))
  748.             (setq base (append base (list (add-count fact))))
  749.         )
  750.     )
  751.     fact
  752. )
  753. ;-------------------------------------------------------------------
  754. ;
  755. ;   Return clause in a list preceded by the clause's literal-count
  756. ;
  757. (defun add-count (clause)
  758.     (list (literal-count clause) clause)
  759. )
  760. ;-------------------------------------------------------------------
  761. ;
  762. ;   Add a clause to the set-of-support -
  763. ;       add (clause X base) to pairs;
  764. ;       add clause to base
  765. ;
  766. (defun add-sos (clause)
  767.     (let
  768.         (
  769.             (pair (list (literal-count clause) clause))
  770.         )
  771.         (mapcar `(lambda (a) (add-pair pair a)) base)
  772.         (setq base (append base (list (add-count clause))))
  773.     )
  774. )
  775. ;-------------------------------------------------------------------
  776. ;
  777. ;   Insert a pair of clauses into pairs - returns pairs
  778. ;
  779. (defun add-pair (q b)
  780.     (let
  781.         (
  782.             (size-q (car q))
  783.             (size-b (car b))
  784.             (q-cl (cadr q))
  785.             (b-cl (cadr b))
  786.             (size 0)
  787.             (new-pair nil)
  788.         )
  789.         (cond
  790.             ((< size-q size-b)
  791.                 (setq size (+ (* 1000 size-q) size-b))
  792.                 (setq pairs (insert-pair (list size q-cl b-cl) pairs))
  793.             )
  794.             (t
  795.                 (setq size (+ (* 1000 size-b) size-q))
  796.                 (setq pairs (insert-pair (list size b-cl q-cl) pairs))
  797.             )
  798.         )
  799.     )
  800. )
  801. ;-------------------------------------------------------------------
  802. ;
  803. ;   Insert pair into pairs list - return new list
  804. ;
  805. (defun insert-pair (pair pair-list)
  806.     (cond
  807.         ((null pair-list) (list pair))
  808.  
  809.         ;  Use <= for "depth-first", < for "breadth-first"
  810.         ((< (car pair) (caar pair-list)) (cons pair pair-list))
  811.         (t (cons (car pair-list) (insert-pair pair (cdr pair-list))))
  812.     )
  813. )
  814. ;-------------------------------------------------------------------
  815. ;
  816. ;   Count the literals in a clause
  817. ;       Ignore a success clause and change 2's to 1 [e.g. (OR (A)) --> (A)]
  818. ;
  819. (defun literal-count (clause)
  820.     (setq clause (remove-success clause))
  821.     (cond
  822.         ((atom clause) 0)
  823.         ((literal-p clause) 1)
  824.         (t (1- (length clause)))
  825.     )
  826. )
  827. ;-------------------------------------------------------------------
  828. ;
  829. ;   Return the clause with any $success$ element removed
  830. ;
  831. (defun remove-success (clause)
  832.     (cond
  833.         ((atom clause) clause)
  834.         (t (remove nil (remove '$success$ clause :test #'deep-member)))
  835.     )
  836. )
  837. ;-------------------------------------------------------------------
  838. ;
  839. ;   Set the types for each name in the new line
  840. ;
  841. ;   Uses the global association list new-names
  842. ;
  843. ;   If a clause is nil, return nil.
  844. ;   If it's an atom, type it as variable or constant with separate routine.
  845. ;   If it's a list, pass the set-types through on mapcar.
  846. ;
  847. (defun set-types (clause)
  848.     (setq new-names nil)
  849.     (set-types* clause)
  850. )
  851. (defun set-types* (clause)
  852.     (cond
  853.         ((null clause) nil)
  854.         ((equal clause 'not) clause)
  855.         ((equal clause 'or) clause)
  856.         ((equal clause 'and) clause)
  857.         ((atom clause) (set-unit-type clause))
  858.         (t (mapcar 'set-types* clause))
  859.     )
  860. )
  861. ;
  862. ;-------------------------------------------------------------------
  863. ;
  864. ;   Set the type for an atom - either constant or variable
  865. ;
  866. ;   For constants:
  867. ;       Add name to names if new.
  868. ;
  869. ;   For variables:
  870. ;       Is the name is already in the new-names list?
  871. ;       Yes : return the associated name.
  872. ;       No  : Is the name in names?
  873. ;             Yes : Find an alternate name, add the substitution pair to
  874. ;                   new-names, add the new name to names with type variable
  875. ;                   and return the new name.
  876. ;             No  : Add the name to names with type variable, add an identity
  877. ;                   pair to new-names, return the original.
  878. ;
  879. (defun set-unit-type (atm)
  880.     (let
  881.         (
  882.             (g-symb atm)        ; Substitution name
  883.             (atm-type 'variable)
  884.             (pair nil)
  885.         )
  886.         (cond
  887.             ((equal (get atm 'type) 'constant) nil)
  888.             ((char> (char (symbol-name atm) 0) #\F)
  889.  
  890.                 ; If first character > F, it's a variable.
  891.                 (setq pair (assoc atm new-names))
  892.                 (cond
  893.                     ((not (null pair)) (setq g-symb (cadr pair)))
  894.                     (t
  895.                         (cond
  896.                             ((member atm names)
  897.                                 (setq g-symb (gensym))
  898.                                 (add-new-name atm g-symb)
  899.                             )
  900.                             (t  (add-new-name atm atm))
  901.                         )
  902.                     )
  903.                 )
  904.             )
  905.         )
  906.         (add-name g-symb)
  907.     )
  908. )
  909. ;
  910. ;-------------------------------------------------------------------
  911. ;
  912. ;   If the atom is not found in names, add it with given type.
  913. ;   Return the atom
  914. ;
  915. (defun add-name (atm)
  916.     (cond
  917.         ((member atm names) atm)
  918.         (t (setq names (cons atm names)))
  919.     )
  920.     (cond
  921.         ((get atm 'type) nil)
  922.         ((char<= (char (symbol-name atm) 0) #\F) (putprop atm 'constant 'type))
  923.         (t (putprop atm 'variable 'type))
  924.     )
  925.     atm
  926. )
  927. ;
  928. ;-------------------------------------------------------------------
  929. ;
  930. ;   Add a new name to the new-names a-list.  Return the substitution
  931. ;   value
  932. ;
  933. (defun add-new-name (x y)
  934.     (setq new-names (cons (list x y) new-names))
  935.     y
  936. )
  937. ;-------------------------------------------------------------------
  938. ;
  939. ;   Find x at any depth in list
  940. ;
  941. (defun deep-member (x lst)
  942.     (cond
  943.         ((equal x lst) t)
  944.         ((atom lst) nil)
  945.         ((deep-member x (car lst)) t)
  946.         (t (deep-member* x (cdr lst)))
  947.     )
  948. )
  949. (defun deep-member* (x lst)     ; To avoid x = cdr
  950.     (cond
  951.         ((null lst) nil)
  952.         ((deep-member x (car lst)) t)
  953.         (t (deep-member* x (cdr lst)))
  954.     )
  955. )
  956. ;-------------------------------------------------------------------
  957. ;
  958. ;   Print prompt and get input
  959. ;
  960. (defun get-input (mode)
  961.     (terpri)
  962.     (cond
  963.         ((equal mode 'assert) (princ "Assert --"))
  964.         (t (princ "Question --"))
  965.     )
  966.     (read)
  967. )
  968. ;
  969. ;-------------------------------------------------------------------
  970. ;
  971. ;   Test if x is a literal
  972. ;
  973. (defun literal-p (x)
  974.     (cond
  975.         ((atom x) nil)
  976.         ((equal (car x) 'not)
  977.             (not (member (caadr x) (cons 'not operators)))
  978.         )
  979.         ((member (car x) operators) nil)
  980.         (t t)
  981.     )
  982. )
  983. ;-------------------------------------------------------------------
  984. ;
  985. ;   Find first literal in x
  986. ;
  987. (defun first-lit (x)
  988.     (cond
  989.         ((atom x) nil)
  990.         ((equal (car x) 'or) (cadr x))
  991.         (t x)
  992.     )
  993. )
  994. ;-------------------------------------------------------------------
  995. ;
  996. ;   Return x with first literal removed (keep OR unless down to one literal
  997. ;
  998. (defun remove-first-lit (x)
  999.     (cond
  1000.         ((atom x) nil)
  1001.         ((literal-p x) nil)       ; If not, must be clause
  1002.         ((equal (car x) '$success$) nil)
  1003.         ((<= (length x) 3) (car (cdr (cdr x))))
  1004.         (t (cons 'or (cdr (cdr x))))
  1005.     )
  1006. )
  1007. ;-------------------------------------------------------------------
  1008. ;
  1009. ;   Count the items in a list - for memory test purposes
  1010. ;
  1011. (defun deep-count (x)
  1012.     (cond
  1013.         ((null x) 0)
  1014.         ((atom x) 1)
  1015.         (t
  1016.             (apply '+ (mapcar 'deep-count x))
  1017.         )
  1018.     )
  1019. )
  1020. ;-------------------------------------------------------------------
  1021. ;
  1022. ;   Set global variables to initial states
  1023. ;
  1024. (defun init-qa ()
  1025.     (setq base nil)
  1026.     (setq names '(not or))
  1027.     (setq show-proof t)
  1028.     (setq show-unify nil)
  1029.     (setq show-pairs nil)
  1030.     (setq max-pairs 400)
  1031.     (putprop 'not       'constant 'type)
  1032.     (putprop 'or        'constant 'type)
  1033.     (putprop '$success$ 'constant 'type)
  1034.     (putprop 'and       'constant 'type)
  1035.     (putprop 'imply     'constant 'type)
  1036.     (putprop 'equiv     'constant 'type)
  1037.     (setq operators '(or and imply equiv))    ; Can't begin a literal
  1038.     (setq mode 'assert)
  1039.     (setq in-line 0)
  1040.     (princ "Type HELP for help.\n\n")
  1041. )
  1042. ;
  1043. ;-------------------------------------------------------------------
  1044. ;
  1045. ;   CLAUSE CONVERSION CODE
  1046. ;
  1047. ;   Convert the fact to clause form
  1048. ;
  1049. (defun clause-convert (fact)
  1050.     (let
  1051.         (
  1052.             (result fact)
  1053.         )
  1054.         (cond
  1055.             ((atom fact) fact)
  1056.             ((literal-p fact) fact)
  1057.             (t
  1058.                 (setq result (cc-equiv result))
  1059.                 (setq result (cc-imply result))
  1060.                 (setq result (cc-push-not result))
  1061.                 (setq result (cc-push-or result))
  1062.                 (setq result (cc-disassoc result))
  1063.                 result
  1064.             )
  1065.         )
  1066.     )
  1067. )
  1068. ;-------------------------------------------------------------------
  1069. ;
  1070. ;   Convert clause form (equiv (a) (b)) -->
  1071. ;           (and (imply (a) (b)) (imply (b) (a)))
  1072. ;
  1073. ;
  1074. (defun cc-equiv (c)
  1075.     (cond
  1076.         ((atom c) c)
  1077.         ((literal-p c) c)
  1078.         ((equal (car c) 'equiv)
  1079.             `(and
  1080.                 (imply ,(cc-equiv (cadr c)) ,(cc-equiv (caddr c)))
  1081.                 (imply ,(cc-equiv (caddr c)) ,(cc-equiv (cadr c)))
  1082.             )
  1083.         )
  1084.         (t (mapcar 'cc-equiv c))
  1085.     )
  1086. )
  1087. ;-------------------------------------------------------------------
  1088. ;
  1089. ;   Convert clause form (imply (a) (b)) -->
  1090. ;       (or (not (a)) (b))
  1091. ;
  1092. ;
  1093. (defun cc-imply (c)
  1094.     (cond
  1095.         ((atom c) c)
  1096.         ((literal-p c) c)
  1097.         ((equal (car c) 'imply)
  1098.             `(or
  1099.                 (not ,(cc-imply (cadr c)))
  1100.                 ,(cc-imply (caddr c))
  1101.             )
  1102.         )
  1103.         (t (mapcar 'cc-imply c))
  1104.     )
  1105. )
  1106. ;-------------------------------------------------------------------
  1107. ;
  1108. ;   Push NOTs down to literals -
  1109. ;       (not (not (a))) --> (a)
  1110. ;       (not (or (a) (b) (c))) --> (and (not (a)) (not (b)) (not (c)))
  1111. ;       (not (and (a) (b) (c))) --> (or (not (a)) (not (b)) (not (c)))
  1112. ;       (not (exist x (...)) --> (all x (not (...)))
  1113. ;       (not (all x (...)) --> (exist x (not (...)))
  1114. ;
  1115. ;
  1116. (defun cc-push-not (c)              ; No prior NOT being pushed
  1117.     (cond
  1118.         ((atom c) c)
  1119.         ((literal-p c) c)
  1120.         ((equal (car c) 'not) (cc-push-not* (cadr c)))
  1121.         (t (mapcar 'cc-push-not c))
  1122.     )
  1123. )
  1124. (defun cc-push-not* (c)             ; Prior NOT being pushed
  1125.     (cond
  1126.         ((atom c) c)
  1127.         ((literal-p c) (lit-negative c))
  1128.         ((equal (car c) 'not) (cc-push-not (cadr c)))
  1129.         ((equal (car c) 'and)
  1130.             (append '(or) (mapcar 'cc-push-not* (cdr c)))
  1131.         )
  1132.         ((equal (car c) 'or)
  1133.             (append '(and) (mapcar 'cc-push-not* (cdr c)))
  1134.         )
  1135.         ((equal (car c) 'exist)
  1136.             (append `(all ,(cadr c)) (mapcar 'cc-push-not* (caddr c)))
  1137.         )
  1138.         ((equal (car c) 'all)
  1139.             (append `(exist ,(cadr c)) (mapcar 'cc-push-not* (caddr c)))
  1140.         )
  1141.     )
  1142. )
  1143. ;----------------------------------------------------------------------
  1144. ;
  1145. ;   Move all the ORs down below the AND's
  1146. ;
  1147. ;
  1148. (defun cc-push-or (c)
  1149.     (cond
  1150.         ((atom c) c)
  1151.         ((literal-p c) c)
  1152.         ((equal (length c) 2) (cadr c))     ; (AND/OR (a)) --> (a)
  1153.  
  1154.         ((equal (car c) 'or)
  1155.             (cc-or-merge
  1156.                 (cc-push-or (cadr c))
  1157.                 (cc-push-or (append '(or) (cddr c)))
  1158.             )
  1159.         )
  1160.         (t (mapcar 'cc-push-or c))
  1161.     )
  1162. )
  1163. ;----------------------------------------------------------------------
  1164. ;
  1165. ;   Merge two cleaned-up forms with an OR
  1166. ;
  1167. ;
  1168. (defun cc-or-merge (x y)
  1169.     (cond
  1170.         ((null x) y)
  1171.         ((null y) (cc-or-merge y x))
  1172.         ((atom x)
  1173.             (princ "Error in cc-or-merge - invalid form ")
  1174.             (print x)
  1175.         )
  1176.         ((atom y) (cc-or-merge y x))
  1177.         ((equal (car x) 'and)
  1178.             (append
  1179.                 '(and)
  1180.                 (mapcar '(lambda (a) (cc-or-merge y a)) (cdr x))
  1181.             )
  1182.         )
  1183.         ((equal (car y) 'and) (cc-or-merge y x))
  1184.         (t `(or ,x ,y))
  1185.     )
  1186. )
  1187. ;----------------------------------------------------------------------
  1188. ;
  1189. ;   Flatten the form by the association rule
  1190. ;
  1191. ;
  1192. (defun cc-disassoc (c)
  1193.     (cond
  1194.         ((atom c) c)
  1195.         ((literal-p c) c)
  1196.  
  1197.         ; (AND/OR (a)) --> (a)
  1198.         ((equal (length c) 2) (cc-disassoc (cadr c)))
  1199.  
  1200.         (t
  1201.             (cc-merge-assoc
  1202.                 (car c)
  1203.                 (cc-disassoc (cadr c))
  1204.                 (cc-disassoc (caddr c))
  1205.             )
  1206.         )
  1207.     )
  1208. )
  1209. ;----------------------------------------------------------------------
  1210. ;
  1211. ;   Merge two cleaned-up forms by association
  1212. ;
  1213. ;
  1214. (defun cc-merge-assoc (op x y)
  1215.     (cond
  1216.         ((null x) y)
  1217.         ((null y) (cc-merge-assoc op y x))
  1218.         ((atom x)
  1219.             (princ "Error in cc-merge-assoc - invalid form ")
  1220.             (print x)
  1221.         )
  1222.         ((atom y) (cc-merge-assoc op y x))
  1223.  
  1224.         (t
  1225.             (append
  1226.                 (list op)
  1227.                 (cond
  1228.                     ((equal (car x) op) (cdr x))
  1229.                     (t (list x))
  1230.                 )
  1231.                 (cond
  1232.                     ((equal (car y) op) (cdr y))
  1233.                     (t (list y))
  1234.                 )
  1235.             )
  1236.         )
  1237.         ((equal (car y) 'and) (cc-merge-assoc y x))
  1238.         (t `(or ,x ,y))
  1239.     )
  1240. )
  1241.  
  1242. (qa)
  1243.